#pragma once
#include <map>
#include <vector>

#include "qbprotocol/include/simple_encoder.h"
/*
        [内存优化][scofined.qi]
        要解决的问题:
        该类尝试解决这样一种场景的内存占用开销,同时保持性能不下降的过分厉害:
        以字符串为主键,来管理一堆尺寸较为庞大的C++结构体对象

        解决思路:
        放进去的时候,将结构体编码压缩成内存紧凑的内置对象
        读取的时候,将内置对象解码成原先的结构体
        也可以:读取的时候,可以采取特殊的方式,来快速获取原先结构体的成员

        现存事实:
        CBondCompanyRep中,以较短字符串(brokerID)作为主键,存储REPORT
        REPORT结构体较大,通过字段成员来使用,且使用广泛,重构成本极大
        统计数据表明,REPORT中绝大多数成员是默认值

        编码结构:
        头部+每个字段的实际内容偏移量+每个字段的实际编码内容
        如果该字段是默认空值,那么不对其内容做编码,直接跳过
        统计数据表明,可以达到29%的压缩率

        其他优化:
        1.KeyString针对短字符串做编码优化,4个字节可以原地表示长度<=3的字符串
        相对之前,std::string则需要24个字节
        2.针对只有少量几个键值对,map对于vector并无性能优势
          考虑到缓存友好vector性能更快,内存占用更少
          因此CBondCompanyRep中使用EncodeBufInfoVector来存储
*/
enum kObjectMetaId {
  kObjectMetaIdReport = 1,
  kObjectMetaIdIssuer = 2,
};
class TableEncoder {
 public:
  char* Encode(const char* data, int size, int metaId, int& length) {
    return qb::base::SimpleEncoder::Get().Encode(data, size, metaId, length);
  }
  int Decode(const void* encodedData, int encodedSize, char* rawData,
             int capcity) {
    return qb::base::SimpleEncoder::Get().Decode(encodedData, encodedSize,
                                                 rawData, capcity);
  }
};
class ReportEncoder {
 public:
  typedef unsigned short ushort;
  enum kType {
    kTypeChar,
    kTypeTime,
    kTypeInt,
    kTypeInt64,
    kTypeDouble,
    kTypeString,
    kTypeCount,
  };
  struct FieldInfo {
    kType type;  // 字段的类型
    int pos;     // 字段的偏移量
    int len;     // 是字段的长度
  };
  class FieldOffset {
   public:
    std::vector<FieldInfo> m_fields;
    int Add(const char* name, kType type, int pos, int len) {
      m_fields.emplace_back(FieldInfo{type, pos, len});
      return m_fields.size() - 1;
    }
  };
  class FieldArray {
   public:
    struct Offset {
      ushort type : 3;  // 原始字段的数据类型
      ushort dft : 1;   // 如果为1,表示是默认值,不需要编码进去
      ushort pos : 12;  // 表示编码后的位置,长度不用指定,后续一个pos会计算出来
     public:
      Offset(ushort t, ushort d, ushort p) : type(t), dft(d), pos(p) {}
    };

   protected:
    ushort m_count;       // 总字段个数
    ushort m_bytes;       // 总字节大小
    Offset m_offsets[1];  // 编码位置数组
   public:
    int GetBytes() const { return m_bytes; }
    int GetFieldCount() const { return m_count; }
    inline const void* GetField(int index) const {
      static const char dft_value[8] = {0, 0, 0, 0, 0, 0, 0, 0};
      if (m_offsets[index].dft) {
        return dft_value;
      }
      return ((const char*)this) + m_offsets[index].pos;
    }
    inline static bool IsDefault(const char* ptr, int size) {
      for (int i = 0; i < size; i++) {
        if (ptr[i] != 0) return false;
      }
      return true;
    }
    static FieldArray* Create(const char* src, const FieldOffset& fields);
    static void Destroy(FieldArray* farray);
    static bool Decode(const FieldArray* farray, char* dest,
                       const FieldOffset& fields);
  };

 protected:
  class MetaInit {
   public:
    FieldOffset m_offsets;
    MetaInit() { InitReport(&m_offsets); }
    void InitReport(FieldOffset* meta);
  };
  static FieldOffset& GetOffsets() {
    static MetaInit meta;
    return meta.m_offsets;
  }

 public:
  static char* Encode(const char* data, int size, int metaId, int& length);
  static int Decode(const void* encodedData, int encodedSize, char* rawData,
                    int capcity);
};
struct EncodeBufInfo {
  char* buf;  // 编码后的数据
  int size;   // 编码后的长度
};
struct KeyValue {
  qb::base::TinyString first;
  EncodeBufInfo second;
};
/*
        可以选用两种容器,CCompanyRepMap中,brokerID个数很少,因此
        选用EncodeBufInfoVector
*/
typedef std::map<qb::base::TinyString, EncodeBufInfo> EncodeBufInfoMap;
typedef std::vector<KeyValue> EncodeBufInfoVector;
template <typename OBJECT, typename ENCODER, int META_ID,
          typename Container = EncodeBufInfoMap>
class ZippedObjectMap {
 public:
  struct ResultPair {
    qb::base::TinyString first;
    OBJECT second;
  };
  // typedef std::map<KeyString, EncodeBufInfo> Container;
  // typedef std::vector<KeyValue> Container;
  typedef typename Container::iterator mapiterator;
  typedef typename Container::const_iterator mapciterator;
  using key_type = qb::base::TinyString;
  using mapped_type = OBJECT;

 public:
  Container m_keyvalues;
  ZippedObjectMap(const ZippedObjectMap&) = delete;

 public:
  ZippedObjectMap() {}
  ~ZippedObjectMap() { clear(); }
  class iterator {
    mapiterator m_itor;
    ZippedObjectMap* m_owner;
    ResultPair* m_result;  // 指向栈上变量的指针
   public:
    iterator(ZippedObjectMap* own, const mapiterator& mit, ResultPair* result)
        : m_owner(own), m_itor(mit), m_result(result) {
      if (m_owner && m_result) m_owner->decode(mit, m_result);
    }
    iterator(const iterator& it)
        : m_itor(it.m_itor), m_owner(it.m_owner), m_result(it.m_result) {}
    ResultPair* operator->() {
      // BASSERT(m_result);
      // BASSERT(m_itor != m_owner->end().m_itor);
      return m_result;
    }
    bool operator!=(const iterator& it) const { return m_itor != it.m_itor; }
    iterator operator++() { return iterator(m_owner, ++m_itor, m_result); }
    iterator operator++(int) { return iterator(m_owner, ++m_itor, m_result); }
    operator mapiterator() { return m_itor; }
  };
  class wrapper {
    ZippedObjectMap& m_container;
    ResultPair m_result;

   public:
    wrapper(ZippedObjectMap& cont) : m_container(cont) {}
    inline iterator begin() { return m_container.begin(&m_result); }
    inline iterator end() { return m_container.end(); }
    inline iterator find(const key_type& key) {
      return m_container.find(key, &m_result);
    }
    inline int size() const { return m_container.size(); }
    inline int bytes() const { return 0; }
    inline void clear() { m_container.clear(); }
    inline void emplace(const key_type& key, const mapped_type& rpt) {
      m_container.emplace(key, rpt);
    }
    inline iterator erase(iterator _Where) {
      return m_container.erase(_Where, &m_result);
    }
  };

  EncodeBufInfo find(const key_type& key) {
    auto it = findImpl<Container>(key);
    if (it == m_keyvalues.end()) return EncodeBufInfo{nullptr, 0};
    return it->second;
  }
  int getall(EncodeBufInfo* infos, int capcity) const {
    if ((int)m_keyvalues.size() > capcity) return -1;
    int i = 0;
    for (auto it = m_keyvalues.begin(); it != m_keyvalues.end(); ++it)
      infos[i++] = it->second;
    return m_keyvalues.size();
  }

 protected:  // 适配两个容器的模板
#ifdef WIN32
  template <typename CONT>
  mapiterator findImpl(const key_type& key) {
    return m_keyvalues.find(key);
  }
  template <>
  mapiterator findImpl<std::vector<KeyValue>>(const key_type& key) {
    for (auto it = m_keyvalues.begin(); it != m_keyvalues.end(); ++it) {
      if (it->first == key) return it;
    }
    return m_keyvalues.end();
  }

  template <typename CONT>
  void emplaceImpl(const key_type& key, const EncodeBufInfo& info) {
    m_keyvalues.emplace(Container::value_type{key, info});
  }
  template <>
  void emplaceImpl<std::vector<KeyValue>>(const key_type& key,
                                          const EncodeBufInfo& info) {
    // 针对vector,覆盖掉vector自身的扩容机制,总是扩充1个,确保没有浪费多余的内存
    if (m_keyvalues.size() >= m_keyvalues.capacity())
      m_keyvalues.reserve(m_keyvalues.capacity() + 1);
    m_keyvalues.emplace_back(Container::value_type{key, info});
  }
#else
  template <typename CONT>
  mapiterator findImpl(const key_type& key) {
    for (auto it = m_keyvalues.begin(); it != m_keyvalues.end(); ++it) {
      if (it->first == key) return it;
    }
    return m_keyvalues.end();
  }

  template <typename CONT>
  void emplaceImpl(const key_type& key, const EncodeBufInfo& info) {
    // 针对vector,覆盖掉vector自身的扩容机制,总是扩充1个,确保没有浪费多余的内存
    if (m_keyvalues.size() >= m_keyvalues.capacity())
      m_keyvalues.reserve(m_keyvalues.capacity() + 1);
    m_keyvalues.emplace_back(typename Container::value_type{key, info});
  }
#endif
 public:
  iterator begin(ResultPair* result) {
    return {this, m_keyvalues.begin(), result};
  }
  iterator end() { return {this, m_keyvalues.end(), nullptr}; }
  iterator find(const key_type& key, ResultPair* result) {
    return {this, findImpl<Container>(key), result};
  }
  int size() const { return m_keyvalues.size(); }
  void clear() {
    for (auto it = m_keyvalues.begin(); it != m_keyvalues.end(); ++it) {
      qb::base::EncodeBuf::Free(it->second.buf);
    }
    m_keyvalues.clear();
  }
  iterator erase(iterator _Where, ResultPair* result) {
    auto it = m_keyvalues.erase((mapiterator)_Where);
    return iterator(this, it, result);
  }
  void emplace(const key_type& key, const OBJECT& rpt) {
    auto it = findImpl<Container>(key);
    if (it != m_keyvalues.end()) {
      const EncodeBufInfo& info = it->second;
      qb::base::EncodeBuf::Free(info.buf);
      m_keyvalues.erase(it);
    }
    int length = 0;
    char* buf =
        ENCODER::Encode((const char*)&rpt, sizeof(rpt), META_ID, length);
    emplaceImpl<Container>(key, EncodeBufInfo{buf, length});
  }

  void decode(const mapiterator& mit, ResultPair* result) {
    // 将迭代器mit指向的数据解码到result中
    if (mit != m_keyvalues.end() && result) {
      result->first = mit->first;
      const EncodeBufInfo& info = mit->second;
      ENCODER::Decode((const void*)info.buf, info.size,
                      (char*)&(result->second), sizeof(OBJECT));
    }
  }
};
